aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/expression.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rprt-engine/src/expression.rs')
-rw-r--r--rprt-engine/src/expression.rs213
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)");
+ }
}