aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src/explainer.rs
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2025-10-18 22:54:24 +0100
committertslil <tslil@posteo.de>2025-10-18 23:52:52 +0100
commit5cf06bab8d5a8c6115df35f6cec652bfd0fd0922 (patch)
treeca412a1f1c0b58f464bb9f5583e028d403e9e63b /rprt-engine/src/explainer.rs
parent16f0479a4e43a58c04796e9aa4d43d92b2655024 (diff)
Parse hooks, these are left associative
Diffstat (limited to 'rprt-engine/src/explainer.rs')
-rw-r--r--rprt-engine/src/explainer.rs93
1 files changed, 65 insertions, 28 deletions
diff --git a/rprt-engine/src/explainer.rs b/rprt-engine/src/explainer.rs
index 9c847f2..38bd41b 100644
--- a/rprt-engine/src/explainer.rs
+++ b/rprt-engine/src/explainer.rs
@@ -1,6 +1,6 @@
use rprt_engine::{expression::*, parser::*, token::*};
-use std::env;
use std::collections::BTreeSet;
+use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
@@ -37,6 +37,8 @@ struct TreeNode {
depth: usize,
children: Vec<usize>,
is_leaf: bool,
+ hook_kind: Option<HookKind>,
+ train_arity: Option<u8>,
}
fn generate_tree(formatted: &str, expr: &Composite) -> String {
@@ -51,11 +53,8 @@ fn generate_tree(formatted: &str, expr: &Composite) -> String {
output.push_str(formatted);
output.push('\n');
- let mut active_bars: BTreeSet<usize> = nodes
- .iter()
- .filter(|n| n.is_leaf)
- .map(|n| n.pos)
- .collect();
+ let mut active_bars: BTreeSet<usize> =
+ nodes.iter().filter(|n| n.is_leaf).map(|n| n.pos).collect();
let mut prev_active = active_bars.clone();
@@ -64,7 +63,11 @@ fn generate_tree(formatted: &str, expr: &Composite) -> String {
.iter()
.filter(|n| n.depth == current_depth && !n.is_leaf)
.collect();
-
+
+ if interior.is_empty() {
+ continue;
+ }
+
let mut next_active = active_bars.clone();
for node in &interior {
for &child in &node.children {
@@ -82,15 +85,40 @@ fn generate_tree(formatted: &str, expr: &Composite) -> String {
}
}
+ let mut spacer = vec![' '; width];
+ for i in 0..width {
+ if prev_active.contains(&i) {
+ spacer[i] = '│';
+ }
+ }
+ output.push_str(&spacer.iter().collect::<String>());
+ output.push('\n');
+
let mut line = vec![' '; width];
for i in 0..width {
let up = prev_active.contains(&i);
let down = next_active.contains(&i);
let in_span = horizontal_spans.iter().any(|(l, r)| *l <= i && i <= *r);
- let left = i > 0 && horizontal_spans.iter().any(|(l, r)| *l <= i - 1 && i - 1 <= *r);
- let right = i + 1 < width && horizontal_spans.iter().any(|(l, r)| *l <= i + 1 && i + 1 <= *r);
-
- if up || down || in_span {
+ let left = i > 0
+ && horizontal_spans
+ .iter()
+ .any(|(l, r)| *l <= i - 1 && i - 1 <= *r);
+ let right = i + 1 < width
+ && horizontal_spans
+ .iter()
+ .any(|(l, r)| *l <= i + 1 && i + 1 <= *r);
+
+ let node_at_pos = interior.iter().find(|n| n.pos == i);
+
+ if let Some(node) = node_at_pos {
+ if let Some(hook_kind) = node.hook_kind {
+ line[i] = hook_kind.to_string().chars().next().unwrap();
+ } else if let Some(arity) = node.train_arity {
+ line[i] = char::from_digit(arity as u32, 10).unwrap();
+ } else if up || down || in_span {
+ line[i] = box_char(up, down, left, right);
+ }
+ } else if up || down || in_span {
line[i] = box_char(up, down, left, right);
}
}
@@ -116,7 +144,16 @@ fn generate_tree(formatted: &str, expr: &Composite) -> String {
output
}
-fn build_tree_from_expr(expr: &Composite, depth: usize, offset: usize, nodes: &mut Vec<TreeNode>) -> usize {
+fn format_width(expr: &Composite) -> usize {
+ format!("{}", expr).chars().count()
+}
+
+fn build_tree_from_expr(
+ expr: &Composite,
+ depth: usize,
+ offset: usize,
+ nodes: &mut Vec<TreeNode>,
+) -> usize {
match expr {
Composite::SelectionFunction { .. } | Composite::TextFunction { .. } => {
nodes.push(TreeNode {
@@ -124,15 +161,15 @@ fn build_tree_from_expr(expr: &Composite, depth: usize, offset: usize, nodes: &m
depth,
children: vec![],
is_leaf: true,
+ hook_kind: None,
+ train_arity: None,
});
offset
}
Composite::Train2 { f, g } => {
- let f_offset = offset + 1;
+ let f_offset = offset + 1; // Account for opening '('
let f_pos = build_tree_from_expr(f, depth + 1, f_offset, nodes);
-
- let f_str = format!("{}", f);
- let g_offset = f_offset + f_str.chars().count() + 1;
+ let g_offset = f_offset + format_width(f) + 1; // +1 for space
let g_pos = build_tree_from_expr(g, depth + 1, g_offset, nodes);
nodes.push(TreeNode {
@@ -140,19 +177,17 @@ fn build_tree_from_expr(expr: &Composite, depth: usize, offset: usize, nodes: &m
depth,
children: vec![f_pos, g_pos],
is_leaf: false,
+ hook_kind: None,
+ train_arity: Some(2),
});
f_pos
}
Composite::Train3 { f, g, h } => {
- let f_offset = offset + 1;
+ let f_offset = offset + 1; // Account for opening '('
let f_pos = build_tree_from_expr(f, depth + 1, f_offset, nodes);
-
- let f_str = format!("{}", f);
- let g_offset = f_offset + f_str.chars().count() + 1;
+ let g_offset = f_offset + format_width(f) + 1; // +1 for space
let g_pos = build_tree_from_expr(g, depth + 1, g_offset, nodes);
-
- let g_str = format!("{}", g);
- let h_offset = g_offset + g_str.chars().count() + 1;
+ let h_offset = g_offset + format_width(g) + 1; // +1 for space
let h_pos = build_tree_from_expr(h, depth + 1, h_offset, nodes);
nodes.push(TreeNode {
@@ -160,15 +195,15 @@ fn build_tree_from_expr(expr: &Composite, depth: usize, offset: usize, nodes: &m
depth,
children: vec![f_pos, g_pos, h_pos],
is_leaf: false,
+ hook_kind: None,
+ train_arity: Some(3),
});
g_pos
}
Composite::Hook { kind, left, right } => {
- let left_pos = build_tree_from_expr(left, depth + 1, offset, nodes);
-
- let left_str = format!("{}", left);
- let kind_str = format!("{}", kind);
- let right_offset = offset + left_str.chars().count() + kind_str.chars().count();
+ let left_offset = offset + 1; // Account for opening '('
+ let left_pos = build_tree_from_expr(left, depth + 1, left_offset, nodes);
+ let right_offset = left_offset + format_width(left) + 1; // +1 for hook operator (< or >)
let right_pos = build_tree_from_expr(right, depth + 1, right_offset, nodes);
nodes.push(TreeNode {
@@ -176,6 +211,8 @@ fn build_tree_from_expr(expr: &Composite, depth: usize, offset: usize, nodes: &m
depth,
children: vec![left_pos, right_pos],
is_leaf: false,
+ hook_kind: Some(*kind),
+ train_arity: None,
});
left_pos
}