diff options
| author | tslil <tslil@posteo.de> | 2025-10-18 22:54:24 +0100 |
|---|---|---|
| committer | tslil <tslil@posteo.de> | 2025-10-18 23:52:52 +0100 |
| commit | 5cf06bab8d5a8c6115df35f6cec652bfd0fd0922 (patch) | |
| tree | ca412a1f1c0b58f464bb9f5583e028d403e9e63b /rprt-engine/src/explainer.rs | |
| parent | 16f0479a4e43a58c04796e9aa4d43d92b2655024 (diff) | |
Parse hooks, these are left associative
Diffstat (limited to 'rprt-engine/src/explainer.rs')
| -rw-r--r-- | rprt-engine/src/explainer.rs | 93 |
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 } |
