calcit/
call_stack.rs

1use crate::data::cirru;
2use crate::data::edn;
3use crate::primes::{Calcit, CalcitItems};
4use cirru_edn::Edn;
5use std::collections::HashMap;
6use std::fmt;
7use std::fs;
8use std::hash::Hash;
9use std::sync::Arc;
10
11#[derive(Debug, PartialEq, Clone, Eq, Ord, PartialOrd, Hash)]
12pub struct CalcitStack {
13  pub ns: Arc<str>,
14  pub def: Arc<str>,
15  pub code: Calcit, // built in functions may not contain code
16  pub args: Box<CalcitItems>,
17  pub kind: StackKind,
18}
19
20#[derive(Debug, PartialEq, Clone, Eq, Ord, PartialOrd, Hash)]
21pub enum StackKind {
22  Fn,
23  Proc,
24  Macro,
25  Syntax,  // rarely used
26  Codegen, // track preprocessing
27}
28
29impl fmt::Display for CalcitStack {
30  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31    write!(f, "TODO")
32  }
33}
34
35pub type CallStackList = rpds::ListSync<CalcitStack>;
36
37// TODO impl fmt
38
39/// create new entry to the tree
40pub fn extend_call_stack(
41  stack: &CallStackList,
42  ns: Arc<str>,
43  def: Arc<str>,
44  kind: StackKind,
45  code: Calcit,
46  args: &CalcitItems,
47) -> CallStackList {
48  stack.push_front(CalcitStack {
49    ns,
50    def,
51    code,
52    args: Box::new(args.to_owned()),
53    kind,
54  })
55}
56
57// show simplified version of stack
58pub fn show_stack(stack: &CallStackList) {
59  println!("\ncall stack:");
60  for s in stack {
61    let is_macro = s.kind == StackKind::Macro;
62    println!("  {}/{}{}", s.ns, s.def, if is_macro { "\t ~macro" } else { "" });
63  }
64}
65
66pub fn display_stack(failure: &str, stack: &CallStackList) -> Result<(), String> {
67  eprintln!("\nFailure: {}", failure);
68  eprintln!("\ncall stack:");
69
70  for s in stack {
71    let is_macro = s.kind == StackKind::Macro;
72    eprintln!("  {}/{}{}", s.ns, s.def, if is_macro { "\t ~macro" } else { "" });
73  }
74
75  let mut stack_list: Vec<Edn> = Vec::with_capacity(stack.len());
76  for s in stack {
77    let mut info: HashMap<Edn, Edn> = HashMap::with_capacity(4);
78    info.insert(Edn::kwd("def"), Edn::str(format!("{}/{}", s.ns, s.def)));
79    info.insert(Edn::kwd("code"), Edn::Quote(cirru::calcit_to_cirru(&s.code)?));
80    let mut args: Vec<Edn> = Vec::with_capacity(s.args.len());
81    for a in &*s.args {
82      args.push(edn::calcit_to_edn(a)?);
83    }
84    info.insert(Edn::kwd("args"), Edn::List(args));
85    info.insert(Edn::kwd("kind"), Edn::kwd(&name_kind(&s.kind)));
86
87    stack_list.push(Edn::Map(info))
88  }
89
90  let mut data: HashMap<Edn, Edn> = HashMap::with_capacity(2);
91  data.insert(Edn::kwd("message"), Edn::str(failure));
92  data.insert(Edn::kwd("stack"), Edn::List(stack_list));
93  let content = cirru_edn::format(&Edn::Map(data), true)?;
94  let _ = fs::write(ERROR_SNAPSHOT, content);
95  eprintln!("\nrun `cat {}` to read stack details.", ERROR_SNAPSHOT);
96  Ok(())
97}
98
99const ERROR_SNAPSHOT: &str = ".calcit-error.cirru";
100
101fn name_kind(k: &StackKind) -> String {
102  match k {
103    StackKind::Fn => String::from("fn"),
104    StackKind::Proc => String::from("proc"),
105    StackKind::Macro => String::from("macro"),
106    StackKind::Syntax => String::from("syntax"),
107    StackKind::Codegen => String::from("codegen"),
108  }
109}