aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/selection_functions/types.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rprt-engine/src/selection_functions/types.rs')
-rw-r--r--rprt-engine/src/selection_functions/types.rs237
1 files changed, 174 insertions, 63 deletions
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))
}
}