diff options
Diffstat (limited to 'rprt-engine/src/selection_functions')
| -rw-r--r-- | rprt-engine/src/selection_functions/function_character.rs | 298 | ||||
| -rw-r--r-- | rprt-engine/src/selection_functions/function_empty.rs | 175 | ||||
| -rw-r--r-- | rprt-engine/src/selection_functions/function_end.rs | 204 | ||||
| -rw-r--r-- | rprt-engine/src/selection_functions/mod.rs | 31 | ||||
| -rw-r--r-- | rprt-engine/src/selection_functions/result_transformation.rs | 47 | ||||
| -rw-r--r-- | rprt-engine/src/selection_functions/types.rs | 237 |
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)) } } |
