sim_lib_view_math/
symbolic.rs1use sim_kernel::{Expr, Symbol};
8use sim_lib_scene::node;
9
10pub const SYMBOLIC_LENS: &str = "view:math-symbolic";
12
13pub fn symbolic_tree(expr: &Expr) -> Expr {
15 match expr {
16 Expr::Call { operator, args } => {
17 let mut nodes = vec![leaf(&format!("op: {}", render_head(operator)))];
18 nodes.extend(args.iter().map(symbolic_tree));
19 branch(&render_head(operator), nodes)
20 }
21 Expr::Infix {
22 operator,
23 left,
24 right,
25 } => branch(
26 &operator.to_string(),
27 vec![symbolic_tree(left), symbolic_tree(right)],
28 ),
29 Expr::Prefix { operator, arg } | Expr::Postfix { operator, arg } => {
30 branch(&operator.to_string(), vec![symbolic_tree(arg)])
31 }
32 Expr::List(items) | Expr::Vector(items) => {
33 branch("seq", items.iter().map(symbolic_tree).collect())
34 }
35 Expr::Symbol(symbol) | Expr::Local(symbol) => leaf(&symbol.as_qualified_str()),
36 Expr::Number(number) => leaf(&number.canonical),
37 Expr::String(text) => leaf(&format!("{text:?}")),
38 Expr::Bool(flag) => leaf(&flag.to_string()),
39 Expr::Nil => leaf("nil"),
40 other => leaf(&format!("{other:?}")),
41 }
42}
43
44fn render_head(operator: &Expr) -> String {
45 match operator {
46 Expr::Symbol(symbol) => symbol.as_qualified_str(),
47 other => format!("{other:?}"),
48 }
49}
50
51fn branch(label: &str, nodes: Vec<Expr>) -> Expr {
52 node(
53 "tree",
54 vec![
55 ("label", Expr::String(label.to_owned())),
56 ("nodes", Expr::List(nodes)),
57 ],
58 )
59}
60
61fn leaf(text: &str) -> Expr {
62 node("text", vec![("text", Expr::String(text.to_owned()))])
63}
64
65pub fn call(operator: &str, args: Vec<Expr>) -> Expr {
67 Expr::Call {
68 operator: Box::new(Expr::Symbol(Symbol::new(operator))),
69 args,
70 }
71}