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, 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, Codegen, }
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
37pub 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
57pub 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}