aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/selection_functions
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2026-08-24 20:39:57 +0100
committertslil <tslil@posteo.de>2026-08-24 21:39:25 +0100
commitf3acb5cc0faf739f09112607bb98b6594184bd8b (patch)
tree9f60aeda21a775f9d34ed8a70fffd9be638f27ce /rprt-engine/src/selection_functions
parent72a5e0fc968e2bea9f7d348c7189ebc15a5b15d3 (diff)
The big transposition-ing: move from functions as data to data of functionsHEADmain
Basically Rust will fight you all the way if you treat it like Haskell, instead work with traits and impls on ZSTs.
Diffstat (limited to 'rprt-engine/src/selection_functions')
-rw-r--r--rprt-engine/src/selection_functions/function_character.rs298
-rw-r--r--rprt-engine/src/selection_functions/function_empty.rs175
-rw-r--r--rprt-engine/src/selection_functions/function_end.rs204
-rw-r--r--rprt-engine/src/selection_functions/mod.rs31
-rw-r--r--rprt-engine/src/selection_functions/result_transformation.rs47
-rw-r--r--rprt-engine/src/selection_functions/types.rs237
6 files changed, 769 insertions, 223 deletions
diff --git a/rprt-engine/src/selection_functions/function_character.rs b/rprt-engine/src/selection_functions/function_character.rs
index b4bbf0f..4b41297 100644
--- a/rprt-engine/src/selection_functions/function_character.rs
+++ b/rprt-engine/src/selection_functions/function_character.rs
@@ -1,91 +1,249 @@
use crate::{
- dispatch_selection_function,
- selection::Selection,
- selection_function,
- selection_functions::types::{SFArguments, SFError, SFResult, get_buffer},
+ buffer::BufferID,
+ expression::SearchModifier,
+ selection::{Interval, Selection},
+ selection_functions::types::{SelectionFunction, SelectionFunctionError, get_buffer},
state::EditorState,
};
-selection_function! {
- name: character,
- param_type: usize,
- niladic: |(param, es): (usize, &EditorState)| {
+pub struct Character;
+
+impl SelectionFunction<usize> for Character {
+ const NAME: &'static str = "character";
+
+ fn niladic(
+ &self,
+ param: &usize,
+ es: &EditorState,
+ ) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, es.current_buffer_id)?;
Ok(Selection::Scalar {
buffer_id: es.current_buffer_id,
- pos: usize::min(param, buf.max_pos())
+ pos: usize::min(*param, buf.max_pos()),
+ })
+ }
- }) },
- monadic_rank0: |_, buffer_id, pos| Ok(Selection::Scalar {buffer_id, pos}),
- monadic_rank1: |(param, _), buffer_id, int| Ok(
- Selection::Scalar {buffer_id, pos: usize::min(int.end, *param)}
- )
+ fn monadic_rank0(
+ &self,
+ _param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar { buffer_id, pos })
+ }
+
+ fn monadic_rank1(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: usize::min(interval.start + *param, interval.end),
+ })
+ }
}
-selection_function!(
- name: sequential_character,
- param_type: usize,
- niladic: |_| Err(SFError::NoNiladicForm(";n").into()),
- monadic_rank0: |(param, es), buffer_id, pos| {
+pub struct SequentialCharacter;
+
+impl SelectionFunction<usize> for SequentialCharacter {
+ const NAME: &'static str = "sequential_character";
+
+ fn niladic(
+ &self,
+ _param: &usize,
+ _es: &EditorState,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";n"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ param: &usize,
+ es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, buffer_id)?;
- Ok(Selection::Scalar {buffer_id, pos: usize::min(pos+*param, buf.max_pos())})
- },
- monadic_rank1: |(param, es), buffer_id, int| {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: usize::min(pos + *param, buf.max_pos()),
+ })
+ }
+
+ fn monadic_rank1(
+ &self,
+ param: &usize,
+ es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, buffer_id)?;
- Ok(Selection::Scalar {buffer_id, pos: usize::min(int.end+*param, buf.max_pos())})
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: usize::min(interval.end + *param, buf.max_pos()),
+ })
}
-);
+}
+
+pub struct ReverseCharacter;
+
+impl SelectionFunction<usize> for ReverseCharacter {
+ const NAME: &'static str = "reverse_character";
-selection_function!(
- name: reverse_character,
- param_type: usize,
- niladic: |(param, es): (usize, &EditorState)| {
+ fn niladic(
+ &self,
+ param: &usize,
+ es: &EditorState,
+ ) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, es.current_buffer_id)?;
Ok(Selection::Scalar {
buffer_id: es.current_buffer_id,
- pos: if buf.max_pos() < param {
+ pos: if buf.max_pos() < *param {
+ 0
+ } else {
+ buf.max_pos() - *param
+ },
+ })
+ }
+
+ fn monadic_rank0(
+ &self,
+ _param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar { buffer_id, pos })
+ }
+
+ fn monadic_rank1(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: if *param < interval.end {
+ interval.end - *param
+ } else {
+ 0
+ },
+ })
+ }
+}
+
+pub struct SequentialReverseCharacter;
+
+impl SelectionFunction<usize> for SequentialReverseCharacter {
+ const NAME: &'static str = "sequential_reverse_character";
+
+ fn niladic(
+ &self,
+ _param: &usize,
+ _es: &EditorState,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";'n"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: if *param < pos { pos - *param } else { 0 },
+ })
+ }
+
+ fn monadic_rank1(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: if *param < interval.end {
+ interval.end - *param
+ } else {
0
+ },
+ })
+ }
+}
+
+pub struct ReverseSequentialCharacter;
+
+impl SelectionFunction<usize> for ReverseSequentialCharacter {
+ const NAME: &'static str = "reverse_sequential_character";
+
+ fn niladic(
+ &self,
+ _param: &usize,
+ _es: &EditorState,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm("';n"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: if *param < pos { pos - *param } else { 0 },
+ })
+ }
+
+ fn monadic_rank1(
+ &self,
+ param: &usize,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: if *param < interval.start {
+ interval.start - *param
} else {
- buf.max_pos() - param
+ 0
},
})
- },
- monadic_rank0: |_, buffer_id, pos| Ok(Selection::Scalar {buffer_id, pos}),
- monadic_rank1: |(param, _), buffer_id, int| Ok(
- Selection::Scalar {buffer_id, pos: usize::min(int.end, *param)}
- )
-);
-
-selection_function!(
- name: sequential_reverse_character,
- param_type: usize,
- niladic: |_| Err(SFError::NoNiladicForm(";'n").into()),
- monadic_rank0: |(param, _), buffer_id, pos| {
- Ok(Selection::Scalar {buffer_id, pos: if *param<pos {pos - *param} else {0}})
- },
- monadic_rank1: |(param, _), buffer_id, int| {
- Ok(Selection::Scalar {buffer_id, pos: if *param<int.end {int.end - *param} else {0}})
- }
-);
-
-selection_function!(
- name: reverse_sequential_character,
- param_type: usize,
- niladic: |_| Err(SFError::NoNiladicForm("';n").into()),
- monadic_rank0: |(param, _), buffer_id, pos| {
- Ok(Selection::Scalar {buffer_id, pos: if *param<pos {pos - *param} else {0}})
- },
- monadic_rank1: |(param, _), buffer_id, int| {
- Ok(Selection::Scalar {buffer_id, pos: if *param<int.start {int.start - *param} else {0}})
- }
-);
-
-dispatch_selection_function!(
- name: selection_function_character,
- param_type: usize,
- base: character,
- sequential: sequential_character,
- reverse: reverse_character,
- sequential_reverse: sequential_reverse_character,
- reverse_sequential: reverse_sequential_character,
-);
+ }
+}
+
+/// Dispatch on the search modifier and apply the matching character-family
+/// function to the supplied selections.
+pub fn selection_function_character(
+ offset: usize,
+ es: &EditorState,
+ left: Option<&Selection>,
+ right: Option<&Selection>,
+ search_mod: Option<SearchModifier>,
+) -> Result<Selection, SelectionFunctionError> {
+ match search_mod {
+ None => Character.apply(&offset, es, left, right),
+ Some(SearchModifier::Sequential) => SequentialCharacter.apply(&offset, es, left, right),
+ Some(SearchModifier::Reverse) => ReverseCharacter.apply(&offset, es, left, right),
+ Some(SearchModifier::SequentialReverse) => {
+ SequentialReverseCharacter.apply(&offset, es, left, right)
+ }
+ Some(SearchModifier::ReverseSequential) => {
+ ReverseSequentialCharacter.apply(&offset, es, left, right)
+ }
+ }
+}
diff --git a/rprt-engine/src/selection_functions/function_empty.rs b/rprt-engine/src/selection_functions/function_empty.rs
index bf0a45c..4b69dcf 100644
--- a/rprt-engine/src/selection_functions/function_empty.rs
+++ b/rprt-engine/src/selection_functions/function_empty.rs
@@ -1,12 +1,175 @@
use crate::{
- selection::Selection,
- selection_functions::types::{SFArguments, SFResult},
+ buffer::BufferID,
+ expression::SearchModifier,
+ selection::{Interval, Selection},
+ selection_functions::types::{
+ SelectionFunction, SelectionFunctionError, UnparameterisedSelectionFunction,
+ },
+ state::EditorState,
};
-pub fn empty_sequential(_: SFArguments) -> SFResult {
- Ok(Selection::empty())
+pub struct Empty;
+
+impl UnparameterisedSelectionFunction for Empty {
+ const NAME: &'static str = "empty";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::empty())
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ _buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::empty())
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ _buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::empty())
+ }
+}
+
+pub struct ReverseEmpty;
+
+impl UnparameterisedSelectionFunction for ReverseEmpty {
+ const NAME: &'static str = "reverse_empty";
+
+ fn niladic(&self, es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(es.current_buffer_id))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+}
+
+pub struct SequentialEmpty;
+
+impl UnparameterisedSelectionFunction for SequentialEmpty {
+ const NAME: &'static str = "sequential_empty";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";e"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+}
+
+pub struct SequentialReverseEmpty;
+
+impl UnparameterisedSelectionFunction for SequentialReverseEmpty {
+ const NAME: &'static str = "sequential_reverse_empty";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";'e"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+}
+
+pub struct ReverseSequentialEmpty;
+
+impl UnparameterisedSelectionFunction for ReverseSequentialEmpty {
+ const NAME: &'static str = "reverse_sequential_empty";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm("';e"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(empty_in_buffer(buffer_id))
+ }
+}
+
+fn empty_in_buffer(buffer_id: BufferID) -> Selection {
+ Selection::Vectors {
+ buffer_id,
+ ranges: Vec::new(),
+ }
}
-pub fn empty_structural(_: SFArguments) -> SFResult {
- Ok(Selection::empty())
+pub fn selection_function_empty(
+ es: &EditorState,
+ left: Option<&Selection>,
+ right: Option<&Selection>,
+ search_mod: Option<SearchModifier>,
+) -> Result<Selection, SelectionFunctionError> {
+ match search_mod {
+ None => Empty.apply(&(), es, left, right),
+ Some(SearchModifier::Sequential) => SequentialEmpty.apply(&(), es, left, right),
+ Some(SearchModifier::Reverse) => ReverseEmpty.apply(&(), es, left, right),
+ Some(SearchModifier::SequentialReverse) => {
+ SequentialReverseEmpty.apply(&(), es, left, right)
+ }
+ Some(SearchModifier::ReverseSequential) => {
+ ReverseSequentialEmpty.apply(&(), es, left, right)
+ }
+ }
}
diff --git a/rprt-engine/src/selection_functions/function_end.rs b/rprt-engine/src/selection_functions/function_end.rs
index 75b4c96..ad161d2 100644
--- a/rprt-engine/src/selection_functions/function_end.rs
+++ b/rprt-engine/src/selection_functions/function_end.rs
@@ -1,57 +1,142 @@
use crate::{
- dispatch_selection_function,
- selection::Selection,
- selection_function,
- selection_functions::types::{SFArguments, SFError, SFResult, get_buffer},
+ buffer::BufferID,
+ expression::SearchModifier,
+ selection::{Interval, Selection},
+ selection_functions::types::{
+ SelectionFunction, SelectionFunctionError, UnparameterisedSelectionFunction, get_buffer,
+ },
state::EditorState,
};
-selection_function! {
- name: end,
- param_type: (),
- niladic: |(_, es): ((), &EditorState)| {
+pub struct End;
+
+impl UnparameterisedSelectionFunction for End {
+ const NAME: &'static str = "end";
+
+ fn niladic(&self, es: &EditorState) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, es.current_buffer_id)?;
Ok(Selection::Scalar {
buffer_id: es.current_buffer_id,
pos: buf.max_pos(),
})
- },
- monadic_rank0: |_, buffer_id, pos | Ok(Selection::Scalar { buffer_id, pos }),
- monadic_rank1: |_, buffer_id, int | Ok(Selection::Scalar { buffer_id, pos: int.end })
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar { buffer_id, pos })
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: interval.end,
+ })
+ }
}
-selection_function! {
- name: reverse_end,
- param_type: (),
- niladic: |(_, es): ((), &EditorState)| {
+pub struct ReverseEnd;
+
+impl UnparameterisedSelectionFunction for ReverseEnd {
+ const NAME: &'static str = "reverse_end";
+
+ fn niladic(&self, es: &EditorState) -> Result<Selection, SelectionFunctionError> {
Ok(Selection::Scalar {
buffer_id: es.current_buffer_id,
pos: 0,
})
- },
- monadic_rank0: |_, buffer_id, pos | Ok(Selection::Scalar { buffer_id, pos }),
- monadic_rank1: |_, buffer_id, int | Ok(Selection::Scalar { buffer_id, pos: int.start })
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar { buffer_id, pos })
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: interval.start,
+ })
+ }
}
-selection_function! {
- name: sequential_end,
- param_type: (),
- niladic: |_| Err(SFError::NoNiladicForm(";$").into()),
- monadic_rank0: |_, buffer_id, pos| Ok(Selection::Scalar { buffer_id, pos }),
- monadic_rank1: |(_, es), buffer_id, _| {
+pub struct SequentialEnd;
+
+impl UnparameterisedSelectionFunction for SequentialEnd {
+ const NAME: &'static str = "sequential_end";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";$"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ es: &EditorState,
+ buffer_id: BufferID,
+ _pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ let buf = get_buffer(es, buffer_id)?;
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: buf.max_pos(),
+ })
+ }
+
+ fn monadic_rank1(
+ &self,
+ es: &EditorState,
+ buffer_id: BufferID,
+ _interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
let buf = get_buffer(es, buffer_id)?;
- Ok(Selection::Scalar { buffer_id, pos: buf.max_pos() })
+ Ok(Selection::Scalar {
+ buffer_id,
+ pos: buf.max_pos(),
+ })
}
}
-selection_function! {
- name: sequential_reverse_end,
- param_type: (),
- niladic: |_| Err(SFError::NoNiladicForm(";'$").into()),
- monadic_rank0: |_, buffer_id, pos| {
+pub struct SequentialReverseEnd;
+
+impl UnparameterisedSelectionFunction for SequentialReverseEnd {
+ const NAME: &'static str = "sequential_reverse_end";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(";'$"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
Ok(Selection::Scalar { buffer_id, pos })
- },
- monadic_rank1: |_, buffer_id, interval| {
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
Ok(Selection::Scalar {
buffer_id,
pos: interval.end,
@@ -59,14 +144,30 @@ selection_function! {
}
}
-selection_function! {
- name: reverse_sequential_end,
- param_type: (),
- niladic: |_| Err(SFError::NoNiladicForm("';$").into()),
- monadic_rank0: |_, buffer_id, pos| {
+pub struct ReverseSequentialEnd;
+
+impl UnparameterisedSelectionFunction for ReverseSequentialEnd {
+ const NAME: &'static str = "reverse_sequential_end";
+
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm("';$"))
+ }
+
+ fn monadic_rank0(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
Ok(Selection::Scalar { buffer_id, pos })
- },
- monadic_rank1: |_, buffer_id, interval| {
+ }
+
+ fn monadic_rank1(
+ &self,
+ _es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
Ok(Selection::Scalar {
buffer_id,
pos: interval.end,
@@ -74,12 +175,19 @@ selection_function! {
}
}
-dispatch_selection_function!(
- name: selection_function_end,
- param_type: (),
- base: end,
- sequential: sequential_end,
- reverse: reverse_end,
- sequential_reverse: sequential_reverse_end,
- reverse_sequential: reverse_sequential_end,
-);
+/// Dispatch on the search modifier and apply the matching end-family
+/// function to the supplied selections.
+pub fn selection_function_end(
+ es: &EditorState,
+ left: Option<&Selection>,
+ right: Option<&Selection>,
+ search_mod: Option<SearchModifier>,
+) -> Result<Selection, SelectionFunctionError> {
+ match search_mod {
+ None => End.apply(&(), es, left, right),
+ Some(SearchModifier::Sequential) => SequentialEnd.apply(&(), es, left, right),
+ Some(SearchModifier::Reverse) => ReverseEnd.apply(&(), es, left, right),
+ Some(SearchModifier::SequentialReverse) => SequentialReverseEnd.apply(&(), es, left, right),
+ Some(SearchModifier::ReverseSequential) => ReverseSequentialEnd.apply(&(), es, left, right),
+ }
+}
diff --git a/rprt-engine/src/selection_functions/mod.rs b/rprt-engine/src/selection_functions/mod.rs
index b753200..85c333e 100644
--- a/rprt-engine/src/selection_functions/mod.rs
+++ b/rprt-engine/src/selection_functions/mod.rs
@@ -3,9 +3,9 @@ use crate::{
selection::Selection,
selection_functions::{
function_character::selection_function_character,
+ function_empty::selection_function_empty,
function_end::selection_function_end,
result_transformation::{complement_transform, conditional_transform},
- types::SFArguments,
},
state::EditorState,
};
@@ -16,7 +16,9 @@ mod function_end;
mod result_transformation;
mod types;
-pub use crate::selection_functions::types::{SFError, SFResult};
+pub use crate::selection_functions::types::{
+ SelectionFunction, SelectionFunctionError, UnparameterisedSelectionFunction,
+};
pub fn evaluate_selection_function(
es: &EditorState,
@@ -25,31 +27,30 @@ pub fn evaluate_selection_function(
result_transform: Option<ResultTransform>,
left: Option<Selection>,
right: Option<Selection>,
-) -> SFResult {
- let sf_args = match (left, right) {
- (None, None) => Ok(SFArguments::Niladic { es }),
- (Some(left), None) => Ok(SFArguments::Monadic { es, left }),
- (Some(left), Some(right)) => Ok(SFArguments::Dyadic { es, left, right }),
- _ => Err(SFError::NoLeftArgument),
- }?;
+) -> Result<Selection, SelectionFunctionError> {
let res = match sf {
BuiltinSelectionFn::CharOffset(off) => {
- selection_function_character(off, &sf_args, search_mod)
+ selection_function_character(off, es, left.as_ref(), right.as_ref(), search_mod)
+ }
+ BuiltinSelectionFn::Empty => {
+ selection_function_empty(es, left.as_ref(), right.as_ref(), search_mod)
+ }
+ BuiltinSelectionFn::EndOfBuffer => {
+ selection_function_end(es, left.as_ref(), right.as_ref(), search_mod)
}
- BuiltinSelectionFn::EndOfBuffer => selection_function_end((), &sf_args, search_mod),
- x => Err(SFError::NotImplemented(x).into()),
+ x => Err(SelectionFunctionError::NotImplemented(x)),
}?;
if let Some(result_transform) = result_transform {
match result_transform {
ResultTransform::Complement => complement_transform(es, res),
- ResultTransform::Conditional => conditional_transform(res, &sf_args),
+ ResultTransform::Conditional => conditional_transform(res, left.as_ref()),
ResultTransform::ConditionalComplement => {
let res = complement_transform(es, res)?;
- conditional_transform(res, &sf_args)
+ conditional_transform(res, left.as_ref())
}
ResultTransform::ComplementConditional => {
- let res = conditional_transform(res, &sf_args)?;
+ let res = conditional_transform(res, left.as_ref())?;
complement_transform(es, res)
}
}
diff --git a/rprt-engine/src/selection_functions/result_transformation.rs b/rprt-engine/src/selection_functions/result_transformation.rs
index c150916..b437afd 100644
--- a/rprt-engine/src/selection_functions/result_transformation.rs
+++ b/rprt-engine/src/selection_functions/result_transformation.rs
@@ -1,16 +1,20 @@
use crate::{
buffer::BufferID,
- selection::{Interval, Selection},
- selection_functions::types::{SFArguments, SFError, SFResult},
+ selection::{Interval, Selection, Vectorisable},
+ selection_functions::types::SelectionFunctionError,
state::EditorState,
};
-pub fn complement_transform(es: &EditorState, result: Selection) -> SFResult {
- fn complement_rank0(
+struct Complement;
+
+impl Vectorisable<(), SelectionFunctionError> for Complement {
+ fn rank0(
+ &self,
+ _param: &(),
es: &EditorState,
buffer_id: BufferID,
pos: usize,
- ) -> Result<Selection, SFError> {
+ ) -> Result<Selection, SelectionFunctionError> {
if let Some(buf) = es.get_buffer(buffer_id) {
let mut ranges = Vec::new();
if pos > 0 {
@@ -22,15 +26,17 @@ pub fn complement_transform(es: &EditorState, result: Selection) -> SFResult {
}
Ok(Selection::Vectors { buffer_id, ranges })
} else {
- Err(SFError::BufferNotFound(buffer_id))
+ Err(SelectionFunctionError::BufferNotFound(buffer_id))
}
}
- fn complement_rank1(
+ fn rank1(
+ &self,
+ _param: &(),
es: &EditorState,
buffer_id: BufferID,
interval: &Interval,
- ) -> Result<Selection, SFError> {
+ ) -> Result<Selection, SelectionFunctionError> {
if let Some(buf) = es.get_buffer(buffer_id) {
let max_pos = buf.max_pos();
if interval.start == 0 && interval.end >= max_pos {
@@ -50,25 +56,24 @@ pub fn complement_transform(es: &EditorState, result: Selection) -> SFResult {
}
Ok(Selection::Vectors { buffer_id, ranges })
} else {
- Err(SFError::BufferNotFound(buffer_id))
+ Err(SelectionFunctionError::BufferNotFound(buffer_id))
}
}
+}
- result.vectorise(es, complement_rank0, complement_rank1)
+pub fn complement_transform(
+ es: &EditorState,
+ result: Selection,
+) -> Result<Selection, SelectionFunctionError> {
+ Complement.vectorise(&(), es, &result)
}
-pub fn conditional_transform(mut result: Selection, arg: &SFArguments) -> SFResult {
+pub fn conditional_transform(
+ mut result: Selection,
+ left: Option<&Selection>,
+) -> Result<Selection, SelectionFunctionError> {
if !result.is_empty() {
- Ok(match arg {
- // TODO: think about this niladic case?
- SFArguments::Niladic { .. } => Selection::empty(),
- SFArguments::Monadic { es: _, left } => left.clone(),
- SFArguments::Dyadic {
- es: _,
- left,
- right: _,
- } => left.clone(),
- })
+ Ok(left.cloned().unwrap_or_else(Selection::empty))
} else {
Ok(result)
}
diff --git a/rprt-engine/src/selection_functions/types.rs b/rprt-engine/src/selection_functions/types.rs
index 6bd94bf..4cd76d3 100644
--- a/rprt-engine/src/selection_functions/types.rs
+++ b/rprt-engine/src/selection_functions/types.rs
@@ -1,13 +1,13 @@
use crate::{
buffer::{Buffer, BufferID},
expression::BuiltinSelectionFn,
- selection::{Selection, VectoriseError},
+ selection::{Interval, Selection, Vectorisable},
state::EditorState,
};
use thiserror::Error;
#[derive(Error, Debug)]
-pub enum SFError {
+pub enum SelectionFunctionError {
#[error("Could not find buffer {0}")]
BufferNotFound(BufferID),
#[error("Function {0} has no dyadic form")]
@@ -20,75 +20,186 @@ pub enum SFError {
NotImplemented(BuiltinSelectionFn),
}
-pub enum SFArguments<'a> {
- Niladic {
- es: &'a EditorState,
- },
- Monadic {
- es: &'a EditorState,
- left: Selection,
- },
- Dyadic {
- es: &'a EditorState,
- left: Selection,
- right: Selection,
- },
-}
+/// A selection function parameterised by `P` (the type of its parameter,
+/// e.g. `usize` for character offsets).
+///
+/// Each concrete function is a zero-sized struct implementing this trait;
+/// the parameter value is passed at call time. The arity of the call
+/// (niladic/monadic/dyadic) is routed by [`SelectionFunction::apply`].
+pub trait SelectionFunction<P>: Vectorisable<P, SelectionFunctionError> {
+ /// Name of the function, used in error messages.
+ const NAME: &'static str;
+
+ /// The monadic form applied to a rank-0 (scalar) element.
+ fn monadic_rank0(
+ &self,
+ param: &P,
+ es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError>;
+
+ /// The monadic form applied to a rank-1 (interval) element.
+ fn monadic_rank1(
+ &self,
+ param: &P,
+ es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError>;
+
+ /// The niladic form.
+ fn niladic(&self, _param: &P, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(Self::NAME))
+ }
+
+ /// The monadic form: vectorise over `left`.
+ fn monadic(
+ &self,
+ param: &P,
+ es: &EditorState,
+ left: &Selection,
+ ) -> Result<Selection, SelectionFunctionError> {
+ self.vectorise(param, es, left)
+ }
+
+ /// The dyadic form.
+ fn dyadic(
+ &self,
+ _param: &P,
+ _es: &EditorState,
+ _left: &Selection,
+ _right: &Selection,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoDyadicForm(Self::NAME))
+ }
-pub type SFResult = Result<Selection, VectoriseError<SFError>>;
-
-#[macro_export]
-macro_rules! selection_function {
- (
- name: $name:ident,
- param_type: $P:ty,
- niladic: $niladic_body:expr,
- monadic_rank0: $monadic_rank0_body:expr,
- monadic_rank1: $monadic_rank1_body:expr
- ) => {
- fn $name(param: $P, arg: &SFArguments) -> SFResult {
- match arg {
- SFArguments::Niladic { es } => ($niladic_body)((param, es)),
- SFArguments::Monadic { es, left } => {
- left.vectorise(&(param, es), $monadic_rank0_body, $monadic_rank1_body)
- }
- SFArguments::Dyadic { .. } => Err(SFError::NoDyadicForm(stringify!($name)).into()),
- }
+ /// Route to the arity form matching the selections supplied.
+ fn apply(
+ &self,
+ param: &P,
+ es: &EditorState,
+ left: Option<&Selection>,
+ right: Option<&Selection>,
+ ) -> Result<Selection, SelectionFunctionError> {
+ match (left, right) {
+ (None, None) => self.niladic(param, es),
+ (Some(left), None) => self.monadic(param, es, left),
+ (Some(left), Some(right)) => self.dyadic(param, es, left, right),
+ (None, Some(_)) => Err(SelectionFunctionError::NoLeftArgument),
}
- };
+ }
}
-#[macro_export]
-macro_rules! dispatch_selection_function {
- (
- name: $name:ident,
- param_type: $P:ty,
- base: $bs:ident,
- sequential: $sq:ident,
- reverse: $rv:ident,
- sequential_reverse: $sr:ident,
- reverse_sequential: $rs:ident,
- ) => {
- pub fn $name(
- param: $P,
- arg: &SFArguments,
- search_mod: Option<crate::expression::SearchModifier>,
- ) -> SFResult {
- match search_mod {
- None => ($bs)(param, arg),
- Some(crate::expression::SearchModifier::Sequential) => ($sq)(param, arg),
- Some(crate::expression::SearchModifier::Reverse) => ($rv)(param, arg),
- Some(crate::expression::SearchModifier::SequentialReverse) => ($sr)(param, arg),
- Some(crate::expression::SearchModifier::ReverseSequential) => ($rs)(param, arg),
- }
- }
- };
+/// Every selection function can vectorise a selection by applying its
+/// monadic rank-0/rank-1 forms to each element.
+impl<P, F: SelectionFunction<P> + ?Sized> Vectorisable<P, SelectionFunctionError> for F {
+ fn rank0(
+ &self,
+ param: &P,
+ es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ self.monadic_rank0(param, es, buffer_id, pos)
+ }
+
+ fn rank1(
+ &self,
+ param: &P,
+ es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ self.monadic_rank1(param, es, buffer_id, interval)
+ }
+}
+
+/// A selection function with no parameter.
+///
+/// Blanket-implements [`SelectionFunction`] with `P = ()`, so
+/// unparameterised functions are callable through the same interface.
+pub trait UnparameterisedSelectionFunction {
+ /// Name of the function, used in error messages.
+ const NAME: &'static str;
+
+ /// The monadic form applied to a rank-0 (scalar) element.
+ fn monadic_rank0(
+ &self,
+ es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError>;
+
+ /// The monadic form applied to a rank-1 (interval) element.
+ fn monadic_rank1(
+ &self,
+ es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError>;
+
+ /// The niladic form.
+ fn niladic(&self, _es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoNiladicForm(Self::NAME))
+ }
+
+ /// The dyadic form.
+ fn dyadic(
+ &self,
+ _es: &EditorState,
+ _left: &Selection,
+ _right: &Selection,
+ ) -> Result<Selection, SelectionFunctionError> {
+ Err(SelectionFunctionError::NoDyadicForm(Self::NAME))
+ }
+}
+
+impl<F: UnparameterisedSelectionFunction + ?Sized> SelectionFunction<()> for F {
+ const NAME: &'static str = <F as UnparameterisedSelectionFunction>::NAME;
+
+ fn monadic_rank0(
+ &self,
+ _param: &(),
+ es: &EditorState,
+ buffer_id: BufferID,
+ pos: usize,
+ ) -> Result<Selection, SelectionFunctionError> {
+ UnparameterisedSelectionFunction::monadic_rank0(self, es, buffer_id, pos)
+ }
+
+ fn monadic_rank1(
+ &self,
+ _param: &(),
+ es: &EditorState,
+ buffer_id: BufferID,
+ interval: &Interval,
+ ) -> Result<Selection, SelectionFunctionError> {
+ UnparameterisedSelectionFunction::monadic_rank1(self, es, buffer_id, interval)
+ }
+
+ fn niladic(&self, _param: &(), es: &EditorState) -> Result<Selection, SelectionFunctionError> {
+ UnparameterisedSelectionFunction::niladic(self, es)
+ }
+
+ fn dyadic(
+ &self,
+ _param: &(),
+ es: &EditorState,
+ left: &Selection,
+ right: &Selection,
+ ) -> Result<Selection, SelectionFunctionError> {
+ UnparameterisedSelectionFunction::dyadic(self, es, left, right)
+ }
}
-pub fn get_buffer(es: &EditorState, buffer_id: BufferID) -> Result<&Buffer, SFError> {
+pub fn get_buffer(
+ es: &EditorState,
+ buffer_id: BufferID,
+) -> Result<&Buffer, SelectionFunctionError> {
if let Some(buf) = es.get_buffer(buffer_id) {
Ok(buf)
} else {
- Err(SFError::BufferNotFound(es.current_buffer_id))
+ Err(SelectionFunctionError::BufferNotFound(es.current_buffer_id))
}
}