aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rprt-engine/src/evaluate.rs48
-rw-r--r--rprt-engine/src/explainer.rs8
-rw-r--r--rprt-engine/src/expression.rs10
-rw-r--r--rprt-engine/src/parser.rs56
-rw-r--r--rprt-engine/src/selection_functions/function_character.rs2
-rw-r--r--rprt-engine/src/selection_functions/function_end.rs2
-rw-r--r--rprt.md10
7 files changed, 86 insertions, 50 deletions
diff --git a/rprt-engine/src/evaluate.rs b/rprt-engine/src/evaluate.rs
index a139aa3..cf60ad4 100644
--- a/rprt-engine/src/evaluate.rs
+++ b/rprt-engine/src/evaluate.rs
@@ -1,5 +1,5 @@
use crate::{
- expression::Composite,
+ expression::{Composite, HookKind},
selection::{Selection, SelectionError, VectoriseError},
selection_functions::{evaluate_selection_function, SFError},
state::{EditorState, GroupedChangeError, StateChange, StateResult},
@@ -19,6 +19,8 @@ pub enum EvaluationError {
IROApplication,
#[error("Not yet implemented {0}")]
UnimplementedError(&'static str),
+ #[error("Hook used in niladic context")]
+ NiladicRightHook,
}
fn commit_if_needed(
@@ -34,7 +36,7 @@ fn commit_if_needed(
}
}
-pub fn evaluate(
+fn _eval(
es: &mut EditorState,
comp: Composite,
left: Option<Selection>,
@@ -59,21 +61,43 @@ pub fn evaluate(
Composite::TextFunction { func, swapped } => {
Err(EvaluationError::UnimplementedError("text function"))
}
- Composite::Hook { kind, left, right } => Err(EvaluationError::UnimplementedError("hook")),
+ Composite::Hook { kind, f, g } => match kind {
+ HookKind::Before => {
+ let (f_result, mut changes) = _eval(es, *f, left.clone(), None, commit)?;
+ changes = commit_if_needed(es, changes, commit);
+ let (sel, g_changes) =
+ _eval(es, *g, Some(f_result), right.or_else(|| left), commit)?;
+ let more_changes = commit_if_needed(es, g_changes, commit);
+ changes.extend(more_changes);
+ Ok((sel, changes))
+ }
+ HookKind::After => {
+ if left.is_none() {
+ return Err(EvaluationError::NiladicRightHook);
+ }
+ let (g_result, mut changes) =
+ _eval(es, *g, right.or_else(|| left.clone()), None, commit)?;
+ changes = commit_if_needed(es, changes, commit);
+ let (sel, f_changes) = _eval(es, *f, left.clone(), Some(g_result), commit)?;
+ let more_changes = commit_if_needed(es, f_changes, commit);
+ changes.extend(more_changes);
+ Ok((sel, changes))
+ }
+ },
Composite::Train2 { f, g } => {
- let (left, mut f_changes) = evaluate(es, *f, left, right, commit)?;
+ let (left, mut f_changes) = _eval(es, *f, left, right, commit)?;
f_changes = commit_if_needed(es, f_changes, commit);
- let (sel, g_changes) = evaluate(es, *g, Some(left), None, commit)?;
+ let (sel, g_changes) = _eval(es, *g, Some(left), None, commit)?;
let more_changes = commit_if_needed(es, g_changes, commit);
f_changes.extend(more_changes);
Ok((sel, f_changes))
}
Composite::Train3 { f, g, h } => {
- let (f_left, mut f_changes) = evaluate(es, *f, left.clone(), right.clone(), commit)?;
+ let (f_left, mut f_changes) = _eval(es, *f, left.clone(), right.clone(), commit)?;
f_changes = commit_if_needed(es, f_changes, commit);
- let (g_right, h_changes) = evaluate(es, *h, left, right, commit)?;
+ let (g_right, h_changes) = _eval(es, *h, left, right, commit)?;
let h_changes = commit_if_needed(es, h_changes, commit);
- let (sel, g_changes) = evaluate(es, *g, Some(f_left), Some(g_right), commit)?;
+ let (sel, g_changes) = _eval(es, *g, Some(f_left), Some(g_right), commit)?;
let g_changes = commit_if_needed(es, g_changes, commit);
f_changes.extend(h_changes);
f_changes.extend(g_changes);
@@ -82,7 +106,7 @@ pub fn evaluate(
Composite::Group { operations } => {
let results: Vec<(Selection, Vec<StateChange>)> = operations
.into_iter()
- .map(|op| evaluate(es, op, left.clone(), right.clone(), commit))
+ .map(|op| _eval(es, op, left.clone(), right.clone(), commit))
.collect::<Result<_, _>>()?;
let (selections, arms) = results.into_iter().unzip();
@@ -100,3 +124,9 @@ pub fn evaluate(
}
}
}
+
+pub fn evaluate(es: &mut EditorState, comp: Composite) -> Result<Selection, EvaluationError> {
+ let (sel, changes) = _eval(es, comp, None, None, true)?;
+ es.commit_changes(changes);
+ Ok(sel)
+}
diff --git a/rprt-engine/src/explainer.rs b/rprt-engine/src/explainer.rs
index e3e99fb..cc0a5c3 100644
--- a/rprt-engine/src/explainer.rs
+++ b/rprt-engine/src/explainer.rs
@@ -208,11 +208,11 @@ fn build_tree_from_expr(
});
g_pos
}
- Composite::Hook { kind, left, right } => {
+ Composite::Hook { kind, f, g } => {
let left_offset = offset + 1;
- let left_pos = build_tree_from_expr(left, depth + 1, left_offset, nodes);
- let right_offset = left_offset + format_width(left) + 1;
- let right_pos = build_tree_from_expr(right, depth + 1, right_offset, nodes);
+ let left_pos = build_tree_from_expr(f, depth + 1, left_offset, nodes);
+ let right_offset = left_offset + format_width(f) + 1;
+ let right_pos = build_tree_from_expr(g, depth + 1, right_offset, nodes);
nodes.push(TreeNode {
pos: left_pos,
diff --git a/rprt-engine/src/expression.rs b/rprt-engine/src/expression.rs
index 3bad172..195da80 100644
--- a/rprt-engine/src/expression.rs
+++ b/rprt-engine/src/expression.rs
@@ -15,8 +15,8 @@ pub enum Composite {
Hook {
kind: HookKind,
- left: Box<Composite>,
- right: Box<Composite>,
+ f: Box<Composite>,
+ g: Box<Composite>,
},
Train2 {
@@ -55,7 +55,7 @@ impl Display for Composite {
TextFunction { func, swapped } => {
write!(fmtr, "{}{func}", if *swapped { "@" } else { "" })
}
- Hook { kind, left, right } => write!(fmtr, "({left}{kind}{right})"),
+ Hook { kind, f, g } => write!(fmtr, "({f}{kind}{g})"),
Train2 { f, g } => write!(fmtr, "({f} {g})"),
Train3 { f, g, h } => write!(fmtr, "({f} {g} {h})"),
Group { operations } => {
@@ -211,12 +211,12 @@ mod tests {
}),
h: Box::new(Composite::Hook {
kind: HookKind::Before,
- left: Box::new(Composite::SelectionFunction {
+ f: Box::new(Composite::SelectionFunction {
func: BuiltinSelectionFn::Empty,
result_transform: None,
search_mod: None,
}),
- right: Box::new(Composite::TextFunction {
+ g: Box::new(Composite::TextFunction {
func: BuiltinTextFn::Delete,
swapped: false,
}),
diff --git a/rprt-engine/src/parser.rs b/rprt-engine/src/parser.rs
index 7b68473..e6a9c0b 100644
--- a/rprt-engine/src/parser.rs
+++ b/rprt-engine/src/parser.rs
@@ -179,8 +179,8 @@ fn parse_function_atom(context: &mut ParseContext) -> Result<Composite, ParseErr
let rest = parse_composition(context)?;
return Ok(Composite::Hook {
kind: HookKind::Before,
- left: Box::new(result),
- right: Box::new(rest),
+ f: Box::new(result),
+ g: Box::new(rest),
});
}
Ok(Token::After) => {
@@ -188,8 +188,8 @@ fn parse_function_atom(context: &mut ParseContext) -> Result<Composite, ParseErr
let rest = parse_composition(context)?;
return Ok(Composite::Hook {
kind: HookKind::After,
- left: Box::new(result),
- right: Box::new(rest),
+ f: Box::new(result),
+ g: Box::new(rest),
});
}
_ => return Ok(result),
@@ -673,7 +673,11 @@ mod tests {
let result = parse(tokens).unwrap();
println!("{:?}", result);
match result {
- Composite::Hook { kind, left, right } => {
+ Composite::Hook {
+ kind,
+ f: left,
+ g: right,
+ } => {
assert_eq!(kind, HookKind::Before);
assert!(matches!(
*left,
@@ -704,15 +708,15 @@ mod tests {
match result {
Composite::Hook {
kind: outer_kind,
- left: outer_left,
- right: outer_right,
+ f: outer_left,
+ g: outer_right,
} => {
assert_eq!(outer_kind, HookKind::After);
match *outer_left {
Composite::Hook {
kind: inner_kind,
- left: inner_left,
- right: inner_right,
+ f: inner_left,
+ g: inner_right,
} => {
assert_eq!(inner_kind, HookKind::After);
assert!(matches!(
@@ -753,8 +757,8 @@ mod tests {
match result {
Composite::Hook {
kind: outer_kind,
- left: outer_left,
- right: outer_right,
+ f: outer_left,
+ g: outer_right,
} => {
assert_eq!(outer_kind, HookKind::After);
assert!(matches!(
@@ -767,8 +771,8 @@ mod tests {
match *outer_right {
Composite::Hook {
kind: inner_kind,
- left: inner_left,
- right: inner_right,
+ f: inner_left,
+ g: inner_right,
} => {
assert_eq!(inner_kind, HookKind::After);
assert!(matches!(
@@ -802,8 +806,8 @@ mod tests {
match result {
Composite::Hook {
kind: k1,
- left: l1,
- right: r1,
+ f: l1,
+ g: r1,
} => {
assert_eq!(k1, HookKind::Before);
assert!(matches!(
@@ -817,8 +821,8 @@ mod tests {
match *r1 {
Composite::Hook {
kind: k2,
- left: l2,
- right: r2,
+ f: l2,
+ g: r2,
} => {
assert_eq!(k2, HookKind::After);
assert!(matches!(
@@ -831,8 +835,8 @@ mod tests {
match *r2 {
Composite::Hook {
kind: k3,
- left: l3,
- right: r3,
+ f: l3,
+ g: r3,
} => {
assert_eq!(k3, HookKind::Before);
assert!(matches!(
@@ -867,7 +871,11 @@ mod tests {
let result = parse(tokens).unwrap();
println!("{:?}", result);
match result {
- Composite::Hook { kind, left, right } => {
+ Composite::Hook {
+ kind,
+ f: left,
+ g: right,
+ } => {
assert_eq!(kind, HookKind::Before);
assert!(matches!(
*left,
@@ -966,8 +974,8 @@ mod tests {
match &operations[0] {
Composite::Hook {
kind: HookKind::After,
- left,
- right,
+ f: left,
+ g: right,
} => {
match left.as_ref() {
Composite::SelectionFunction {
@@ -1014,8 +1022,8 @@ mod tests {
match g.as_ref() {
Composite::Hook {
kind: HookKind::After,
- left,
- right,
+ f: left,
+ g: right,
} => {
match left.as_ref() {
Composite::SelectionFunction {
diff --git a/rprt-engine/src/selection_functions/function_character.rs b/rprt-engine/src/selection_functions/function_character.rs
index 94c0963..87bda3d 100644
--- a/rprt-engine/src/selection_functions/function_character.rs
+++ b/rprt-engine/src/selection_functions/function_character.rs
@@ -2,7 +2,7 @@ use crate::{
dispatch_selection_function,
selection::Selection,
selection_function,
- selection_functions::types::{get_buffer, SFArguments, SFError, SFResult},
+ selection_functions::types::{SFArguments, SFError, SFResult, get_buffer},
state::EditorState,
};
diff --git a/rprt-engine/src/selection_functions/function_end.rs b/rprt-engine/src/selection_functions/function_end.rs
index cec7c90..44aab90 100644
--- a/rprt-engine/src/selection_functions/function_end.rs
+++ b/rprt-engine/src/selection_functions/function_end.rs
@@ -2,7 +2,7 @@ use crate::{
dispatch_selection_function,
selection::Selection,
selection_function,
- selection_functions::types::{get_buffer, SFArguments, SFError, SFResult},
+ selection_functions::types::{SFArguments, SFError, SFResult, get_buffer},
state::EditorState,
};
diff --git a/rprt.md b/rprt.md
index f036c43..769df6c 100644
--- a/rprt.md
+++ b/rprt.md
@@ -99,8 +99,8 @@ RPRT provides two explicit hook combinators from BQN for flexible function compo
**After (Right Hook)** `F<G`:
- Niladic: `F<G = ???` TODO: undefined?
-- Monadic: `ω (F<G) = ω F (G ω)`
-- Dyadic: `ω (F<G) α = ω F (G α)`
+- Monadic: `ω (F<G) = ω F (ω G)`
+- Dyadic: `ω (F<G) α = ω F (α G)`
These combinators bind more tightly than trains and enable partial application patterns. Hooks are **right-associative**, the _opposite_ of BQN's modifier associativity: `F<G<H` parses as `F<(G<H)`.
@@ -218,10 +218,8 @@ Because top-level expressions are evaluated niladically (§1.5), searching requi
**Search from buffer start:** `/re/`
Niladic application searches from beginning of buffer
-**Search within current selection:** `.>/re/`
-In the niladic form this is `(.) /re/` (left hook semantics, §1.2), and `.` niladically is the current selection (§3.1). Thus `.>/re/` applies `/re/` to the current selection.
-
-The After hook `F<G` has niladic semantics `F (G)`, making `.< /re/` evaluate to `/re/ (.)`—applying the search function to the current selection.
+**Search within current selection:** `.>/re/` or `./re/`
+In the niladic form this is `(.) /re/` (left hook semantics §1.2, or left associativity), and `.` niladically is the current selection (§3.1). Thus both `.>/re/` and `./re/` apply `/re/` to the current selection.
## 2.2 Selection Function Operators