aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/selection_functions
diff options
context:
space:
mode:
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))
}
}