diff options
Diffstat (limited to 'rprt-engine/src/expression.rs')
| -rw-r--r-- | rprt-engine/src/expression.rs | 213 |
1 files changed, 164 insertions, 49 deletions
diff --git a/rprt-engine/src/expression.rs b/rprt-engine/src/expression.rs index 1ee898e..c463fca 100644 --- a/rprt-engine/src/expression.rs +++ b/rprt-engine/src/expression.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + #[derive(Debug, Clone, PartialEq)] pub enum Composite { SelectionFunction { @@ -29,74 +31,187 @@ pub enum Composite { }, } -#[derive(Debug, Clone, PartialEq)] -pub enum TextFn { - Function { - func: BuiltinTextFn, - swapped: bool, - }, +impl Display for Composite { + fn fmt(&self, fmtr: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::expression::Composite::*; + fn s<T: Display>(x: &Option<T>) -> String { + if let Some(x) = x { + x.to_string() + } else { + String::new() + } + } - Hook { - kind: HookKind, - left: Box<TextFn>, - right: Box<TextFn>, - }, - - Train2 { - f: Box<TextFn>, - g: Box<TextFn>, - }, - - Train3 { - f: Box<TextFn>, - g: Box<TextFn>, - h: Box<TextFn>, - }, + match self { + SelectionFunction { + func, + search_mod, + result_transform, + } => write!(fmtr, "{}{}{func}", s(result_transform), s(search_mod)), + TextFunction { func, swapped } => { + write!(fmtr, "{}{func}", if *swapped { "@" } else { "" }) + } + Hook { kind, left, right } => write!(fmtr, "{left}{kind}{right}",), + Train2 { f, g } => write!(fmtr, "({f} {g})"), + Train3 { f, g, h } => write!(fmtr, "({f} {g} {h})"), + } + } } #[derive(Debug, Clone, PartialEq)] pub enum BuiltinSelectionFn { - Empty, // e - EndOfBuffer, // $ - Span, // - - CharOffset(usize), // # (expects number arg) - Line(usize), // (expects number arg) - Regex(String), // /re/ (expects regex arg) - AllMatches(String), // x (expects /re/ arg) - RelativeLine(usize), // + (expects number arg) - BufferMatch(String), // B (expects /re/ arg) + Empty, + EndOfBuffer, + Span, + CharOffset(usize), + Line(usize), + Regex(String), + AllMatches(String), + RelativeLine(usize), + BufferMatch(String), +} + +impl Display for BuiltinSelectionFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::expression::BuiltinSelectionFn::*; + match self { + Empty => write!(f, "e"), + EndOfBuffer => write!(f, "$"), + Span => write!(f, "-"), + CharOffset(pos) => write!(f, "#{}", pos), + Line(pos) => write!(f, "{}", pos), + Regex(pat) => write!(f, "/{}/", pat), + AllMatches(pat) => write!(f, "x/{}/", pat), + RelativeLine(pos) => write!(f, "+{}", pos), + BufferMatch(pat) => write!(f, "B/{}/", pat), + } + } } #[derive(Debug, Clone, PartialEq)] pub enum BuiltinTextFn { - Dot, // . - Change, // c - Insert, // i - Append, // a - Delete, // d - Write, // w - Pipe, // | - Literal(String), // "..." + Dot, + Change, + Insert, + Append, + Delete, + Write, + Pipe, + Literal(String), +} + +impl Display for BuiltinTextFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::expression::BuiltinTextFn::*; + match self { + Dot => write!(f, "."), + Change => write!(f, "c"), + Insert => write!(f, "i"), + Append => write!(f, "a"), + Delete => write!(f, "d"), + Write => write!(f, "w"), + Pipe => write!(f, "|"), + Literal(s) => write!(f, "\"{}\"", s), + } + } } #[derive(Debug, Clone, Copy, PartialEq)] pub enum SearchModifier { - Reverse, // ' - Sequential, // ; - ReverseSequential, // '; - SequentialReverse, // ;' + Reverse, + Sequential, + ReverseSequential, + SequentialReverse, +} + +impl Display for SearchModifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::expression::SearchModifier::*; + match self { + Reverse => write!(f, "'"), + Sequential => write!(f, ";"), + ReverseSequential => write!(f, "';"), + SequentialReverse => write!(f, ";'"), + } + } } #[derive(Debug, Clone, Copy, PartialEq)] pub enum ResultTransform { - Complement, // ~ - Conditional, // ? - ComplementConditional, // ~? - ConditionalComplement, // ?~ + Complement, + Conditional, + ComplementConditional, + ConditionalComplement, +} + +impl Display for ResultTransform { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::expression::ResultTransform::*; + match self { + Complement => write!(f, "~"), + Conditional => write!(f, "?"), + ComplementConditional => write!(f, "~?"), + ConditionalComplement => write!(f, "?~"), + } + } } #[derive(Debug, Clone, Copy, PartialEq)] pub enum HookKind { - Before, // F>G (left hook) - After, // F<G (right hook) + Before, + After, +} + +impl Display for HookKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + HookKind::Before => write!(f, ">"), + HookKind::After => write!(f, "<"), + } + } +} + +#[cfg(test)] +mod tests { + use crate::expression::*; + + #[test] + fn format_3train() { + // nonsense, but it exercises the code + let comp = Composite::Train3 { + f: Box::new(Composite::SelectionFunction { + func: BuiltinSelectionFn::AllMatches(String::from("re")), + result_transform: Some(ResultTransform::Complement), + search_mod: Some(SearchModifier::Reverse), + }), + g: Box::new(Composite::Train2 { + f: Box::new(Composite::TextFunction { + func: BuiltinTextFn::Change, + swapped: false, + }), + g: Box::new(Composite::SelectionFunction { + func: BuiltinSelectionFn::Line(5), + result_transform: None, + search_mod: None, + }), + }), + h: Box::new(Composite::Hook { + kind: HookKind::Before, + left: Box::new(Composite::SelectionFunction { + func: BuiltinSelectionFn::Empty, + result_transform: None, + search_mod: None, + }), + right: Box::new(Composite::TextFunction { + func: BuiltinTextFn::Delete, + swapped: false, + }), + }), + }; + + let formatted = format!("{}", comp); + println!("Formatted: {}", formatted); + + assert_eq!(formatted, "(~'x/re/ (c 5) e>d)"); + } } |
