bynk_check/ast_text.rs
1//! Short source-text renderings of AST fragments, shared by the agent state
2//! model ([`crate::agent_state`]) and `bynk-ide`'s sequence diagram and effect
3//! summary: a branch's outcome, a match arm's pattern, and a parenthesis peel.
4//! #2220 moved them here from `bynk-ide`'s `sequence.rs` with the state model.
5
6use bynk_syntax::ast::*;
7
8/// A branch's rendered outcome — the tail value the handler yields on that
9/// path (`Ok(view)`), which a renderer shows as a note over the entry
10/// lifeline. `None` when the tail carries no distinguishable reply: a unit
11/// `()` (an else-less `if`'s synthesised branch, or an explicit `()` tail), or
12/// control flow (`if`/`match`/block) that is already rendered as its own
13/// nested structure — repeating it as a note would only add noise.
14pub fn branch_outcome(tail: &Expr) -> Option<String> {
15 let inner = peel_paren(tail);
16 match &inner.kind {
17 ExprKind::UnitLit | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::Block(_) => {
18 None
19 }
20 _ => Some(bynk_fmt::expr_to_string(inner)),
21 }
22}
23
24pub fn peel_paren(expr: &Expr) -> &Expr {
25 match &expr.kind {
26 ExprKind::Paren(inner) => peel_paren(inner),
27 _ => expr,
28 }
29}
30
31/// A match arm's branch label — a short rendering of its pattern, since
32/// there is no dedicated pattern-to-source printer to reuse.
33pub fn pattern_summary(pattern: &Pattern) -> String {
34 match pattern {
35 Pattern::Wildcard(_) => "_".to_string(),
36 Pattern::Binding(b) => b.name.clone(),
37 Pattern::Literal { value, .. } => value.describe(),
38 Pattern::Variant {
39 type_name, variant, ..
40 } => match type_name {
41 Some(t) => format!("{}.{}", t.name, variant.name),
42 None => variant.name.clone(),
43 },
44 Pattern::Refined { inner, .. } => pattern_summary(inner),
45 Pattern::Or(patterns, _) => patterns
46 .iter()
47 .map(pattern_summary)
48 .collect::<Vec<_>>()
49 .join(" | "),
50 }
51}